﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Assist;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Controls;
using YArchitech.Revit;

namespace YArchitech.Plumbing
{
	[Transaction(TransactionMode.Manual)]
	[Regeneration(RegenerationOption.Manual)]
	public class SystemUpDown : IExternalCommand
	{
		public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
		{
			UIDocument activeUIDocument = commandData.Application.ActiveUIDocument;
			Selection selection = activeUIDocument.Selection;
			Document document = commandData.Application.ActiveUIDocument.Document;
			if (!YJKRevitTools.ViewCheck(activeUIDocument, new List<ViewType>
			{
				(ViewType)1,
				(ViewType)2,
				(ViewType)4,
				(ViewType)3
			}))
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			Transaction transaction = null;
			Result result;
			try
			{
				transaction = new Transaction(document, "系统升降");
				transaction.Start();
				RevitVersionFuncs.ClearSelection(selection);
				Reference reference = selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)1, new DuctAndPipeFilter(), "请点取要升降的基本管道：");
				SearchBranch searchBranch = new SearchBranch(document.GetElement(reference));
				searchBranch.DoSearch();
				ElementNode listRoot = searchBranch.GetListRoot();
				List<ElementNode> list = new List<ElementNode>();
				list = this.GetAllElemNode(listRoot, ref list);
				List<Element> list2 = new List<Element>();
				foreach (ElementNode elementNode in list)
				{
					if (!selection.GetElementIds().Contains(elementNode.Element.Id))
					{
						list2.Add(elementNode.Element);
					}
				}
				RevitVersionFuncs.SetSelection(selection, list2);
				SystemUpDownForm systemUpDownForm = new SystemUpDownForm();
				systemUpDownForm.ShowDialog();
				if (systemUpDownForm.DialogResult == DialogResult.Cancel)
				{
					transaction.RollBack();
					result = Autodesk.Revit.UI.Result.Cancelled;
				}
				else if (!this.DealElement(selection, systemUpDownForm.systemUpStyle, systemUpDownForm.dUpDown, document, reference))
				{
					transaction.RollBack();
					result = Autodesk.Revit.UI.Result.Cancelled;
				}
				else
				{
					transaction.Commit();
					result = Autodesk.Revit.UI.Result.Succeeded;
				}
			}
			catch (Autodesk.Revit.Exceptions.OperationCanceledException)
			{
				if (transaction != null && transaction.HasStarted() && !transaction.HasEnded())
				{
					transaction.RollBack();
				}
				result = Autodesk.Revit.UI.Result.Cancelled;
			}
			catch (Exception ex)
			{
				message = ex.Message;
				YJKMessageBox.Show(message);
				if (transaction != null && transaction.HasStarted() && !transaction.HasEnded())
				{
					transaction.RollBack();
				}
				result = Autodesk.Revit.UI.Result.Failed;
			}
			return result;
		}

		public ElementSet GetSystemElementSet(Autodesk.Revit.DB.Document doc, Reference elemRef)
		{
			string paramValue = doc.GetElement(elemRef).GetParameter(BuiltInParameter.RBS_SYSTEM_NAME_PARAM).AsString();
			return new HYSystemElementFilter(doc).GetElemSetByParamValue((BuiltInParameter)(-1140324), paramValue);
		}

		private List<ElementNode> GetAllElemNode(ElementNode eNode, ref List<ElementNode> listENode)
		{
			if (eNode == null)
			{
				return listENode;
			}
			listENode.Add(eNode);
			this.GetAllElemNode(eNode.Next, ref listENode);
			if (eNode.SubElementNode != null)
			{
				foreach (ElementNode eNode2 in eNode.SubElementNode)
				{
					this.GetAllElemNode(eNode2, ref listENode);
				}
			}
			return listENode;
		}

		private bool DealElement(ElementSet elems, int nUpStyle, double dUpValue, Autodesk.Revit.DB.Document doc)
		{
			if (nUpStyle != 0)
			{
				if (nUpStyle != 1)
				{
					goto IL_1E8;
				}
			}
			else
			{
				if (this.IsRiserPipeorDuct(elems))
				{
					YJKMessageBox.Show("选中的系统中有立管，不能使用“升降至”方法处理！");
					return false;
				}
				IEnumerator enumerator = elems.GetEnumerator();
				{
					while (enumerator.MoveNext())
					{
						object obj = enumerator.Current;
						((Element)obj).GetParameter(BuiltInParameter.RBS_OFFSET_PARAM).Set(dUpValue * 1000.0 / 304.8);
					}
					goto IL_1E8;
				}
			}
			Dictionary<Element, double> dictionary = new Dictionary<Element, double>();
			foreach (object obj2 in elems)
			{
				Element element = (Element)obj2;
				if (!this.IsRiserPipeorDuct(element))
				{
					Parameter parameter = element.GetParameter(BuiltInParameter.RBS_OFFSET_PARAM);
					dictionary.Add(element, parameter.AsDouble());
				}
			}
			if (dUpValue > 0.0)
			{
                IEnumerator<KeyValuePair<Element, double>> enumerator2 = (from c in dictionary
                                                                          orderby c.Value descending
                                                                          select c).GetEnumerator();
				{
					while (enumerator2.MoveNext())
					{
						KeyValuePair<Element, double> keyValuePair = enumerator2.Current;
						keyValuePair.Key.GetParameter(BuiltInParameter.RBS_OFFSET_PARAM).Set(keyValuePair.Value + dUpValue * 1000.0 / 304.8);
					}
					goto IL_1E8;
				}
			}
			foreach (KeyValuePair<Element, double> keyValuePair2 in from c in dictionary
			orderby c.Value
			select c)
			{
				keyValuePair2.Key.GetParameter(BuiltInParameter.RBS_OFFSET_PARAM).Set(keyValuePair2.Value + dUpValue * 1000.0 / 304.8);
			}
			IL_1E8:
			doc.Regenerate();
			return true;
		}

		private bool DealElement(Selection sel, int nUpStyle, double dUpValue, Autodesk.Revit.DB.Document doc, Reference elemRef)
		{
			if (nUpStyle != 0)
			{
				if (nUpStyle == 1)
				{
					ElementTransformUtils.MoveElements(doc, sel.GetElementIds(), new XYZ(0.0, 0.0, 1.0) * (dUpValue * 1000.0 / 304.8));
				}
			}
			else
			{
				XYZ globalPoint = elemRef.GlobalPoint;
				double num = doc.GetElement(elemRef).GetParameter(BuiltInParameter.RBS_OFFSET_PARAM).AsDouble();
				ElementTransformUtils.MoveElements(doc, sel.GetElementIds(), new XYZ(0.0, 0.0, 1.0) * (dUpValue * 1000.0 / 304.8 - num));
			}
			doc.Regenerate();
			return true;
		}

		private bool IsRiserPipeorDuct(ElementSet elems)
		{
			bool result = false;
			foreach (object obj in elems)
			{
				Element element = (Element)obj;
				if (element is Pipe)
				{
					Pipe pipe = element as Pipe;
					XYZ hyendPoint = (pipe.Location as LocationCurve).Curve.GetEndPoint(0);
					XYZ hyendPoint2 = (pipe.Location as LocationCurve).Curve.GetEndPoint(1);
					if (Math.Abs(hyendPoint.X - hyendPoint2.X) < 1E-05 && Math.Abs(hyendPoint.Y - hyendPoint2.Y) < 1E-05 && Math.Abs(hyendPoint.Z - hyendPoint2.Z) > 0.015)
					{
						result = true;
					}
				}
				else if (element is Duct)
				{
					Duct duct = element as Duct;
					XYZ hyendPoint3 = (duct.Location as LocationCurve).Curve.GetEndPoint(0);
					XYZ hyendPoint4 = (duct.Location as LocationCurve).Curve.GetEndPoint(1);
					if (Math.Abs(hyendPoint3.X - hyendPoint4.X) < 1E-05 && Math.Abs(hyendPoint3.Y - hyendPoint4.Y) < 1E-05 && Math.Abs(hyendPoint3.Z - hyendPoint4.Z) > 0.015)
					{
						result = true;
					}
				}
			}
			return result;
		}

		private bool IsRiserPipeorDuct(Element elem)
		{
			bool result = false;
			if (elem is Pipe)
			{
				Pipe pipe = elem as Pipe;
				XYZ hyendPoint = (pipe.Location as LocationCurve).Curve.GetEndPoint(0);
				XYZ hyendPoint2 = (pipe.Location as LocationCurve).Curve.GetEndPoint(1);
				if (Math.Abs(hyendPoint.X - hyendPoint2.X) < 1E-05 && Math.Abs(hyendPoint.Y - hyendPoint2.Y) < 1E-05 && Math.Abs(hyendPoint.Z - hyendPoint2.Z) > 0.015)
				{
					result = true;
				}
			}
			else if (elem is Duct)
			{
				Duct duct = elem as Duct;
				XYZ hyendPoint3 = (duct.Location as LocationCurve).Curve.GetEndPoint(0);
				XYZ hyendPoint4 = (duct.Location as LocationCurve).Curve.GetEndPoint(1);
				if (Math.Abs(hyendPoint3.X - hyendPoint4.X) < 1E-05 && Math.Abs(hyendPoint3.Y - hyendPoint4.Y) < 1E-05 && Math.Abs(hyendPoint3.Z - hyendPoint4.Z) > 0.015)
				{
					result = true;
				}
			}
			return result;
		}
	}
}
